//
// Created by Administrator on 2020/1/14.
//

#include <dlfcn.h>
#include "module_manager.h"
#include "log_utils.h"

#define LOG_TAG "ModuleManager"

Module::Module(const std::string &path) {
    const char* p_path=path.c_str();
    mReady=false;
    //Handle
    mHandle= dlopen(p_path,RTLD_NOW);
    if(!mHandle)
        goto err_out;
    AKTagLog("mHandle:%p\n",mHandle);
    //GetModuleName
    mName.clear();
    if(!GetName())
        goto err_out;
    //OnCreateVM
    mOnCreateVM= reinterpret_cast<func_on_create_vm>(dlsym(mHandle, "OnCreateVM"));
    if(!mOnCreateVM)
        goto err_out;
    AKTagLog("mOnCreateVM:%p\n",mOnCreateVM);
    mReady=true;//允许添加到ModuleManager
    return;
    err_out:{
        mReady=false;
        AKTagLogErr("path:%s is not a riru module\n",p_path);
        delete this;
        return;
    }
}

Module::~Module() {
    AKTagLog("attempt to finalize module\n");
    mOnCreateVM= nullptr;
    if(mHandle) {
        AKTagLog("dlclose module handle:%p\n",mHandle);
        dlclose(mHandle);
    }
}

bool Module::GetName() {
    if(!mName.empty()) {
        return true;
    }
    if(!mHandle)
        return false;
    func_get_module_name funcGetModuleName= reinterpret_cast<func_get_module_name>(dlsym(mHandle,
            "GetModuleName"));
    if(!funcGetModuleName)
        return false;
    AKTagLog("get_module_name:%p\n",funcGetModuleName);
    mName= funcGetModuleName();
    AKTagLog("module name:%s\n",mName.c_str());
    return true;
}

void ModuleManager::Add(Module *module) {
    if(!module)
        return;
    if(!module->mReady){
        AKTagLogErr("cannot add a module that is not ready\n");
        return;
    }
    const char* p_name=module->mName.c_str();
    if(mModuleMap.find(module->mName)!=mModuleMap.end()){
        AKTagLogErr("re-add module:%s is not allowed\n",p_name);
        return;
    }
    AKTagLog("add module:%s\n",p_name);
    mModuleMap.insert(std::make_pair(module->mName,module));
}

Module *ModuleManager::Get(const std::string &name) {
    auto itor= mModuleMap.find(name);
    if(itor==mModuleMap.end()) {
        AKTagLogErr("fail to find module:%s\n",name.c_str());
        return nullptr;
    }
    return itor->second;
}
